/**
 * @fileoverview
 * This script defines a widget for interacting with image data from FlyTED.
 * @requires flyui.util
 * @requires flyui.sparql.Service
 * @requires flyui.flyted.Service
 * @requires YAHOO.util.Connect
 * @requires jQuery
 * For license terms see http://flyui.googlecode.com
 */
 
flyui.namespace("flyui.flyted");
 
 

/*
 * ----------------------------------------------------------------
 *                             WIDGET
 * ----------------------------------------------------------------
 */







flyui.flyted.BatchWidget = function( service, renderer ) {
    var _context = "flyui.flyted.BatchWidget";
    try {
        
        flyui.debug("call private constructor", _context);
        this.__init__(service, renderer);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
    
}



 
 



/** @private */
flyui.flyted.BatchWidget.prototype._controller = null;

/**
 * @private
 * @type flyui.mvcutils.GenericModel2
 */ 
flyui.flyted.BatchWidget.prototype._model = null;

/**
 * @private
 */
flyui.flyted.BatchWidget.prototype._renderer = null;

/**
 * @private
 */
flyui.flyted.BatchWidget.prototype._service = null;










/**
 * @private
 */
flyui.flyted.BatchWidget.prototype.__init__ = function( service, renderer ) {
    var _context = "flyui.flyted.BatchWidget.prototype.__init__";
    try {
        
        this._service = service;
        this._renderer = renderer;
        
        flyui.debug("create a model", _context);
        this._model = new flyui.mvcutils.GenericModel2();
        this._model.setDefinition(flyui.flyted.BatchWidget.modelDefinition);
        
        flyui.debug("create a controller", _context);
        this._controller = new flyui.flyted.BatchWidget.Controller(this._model, service, this);
        
        flyui.debug("connect the renderer to the model", _context);
        this._renderer.connect(this._model);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};







/**
 * @public
 * @param {Array<String>} querynames
 * @param {Array<flyui.flybase.Gene>} genes
 */
flyui.flyted.BatchWidget.prototype.findImagesByGeneBatch = function( querynames, genes ) {
    var _context = "flyui.flyted.BatchWidget.prototype.findGenesByAnyNameBatch";
    try {
        
        flyui.debug("pass ["+querynames+"], ["+genes+"] through to controller", _context);
        this._controller.findImagesByGeneBatch(querynames, genes);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};









flyui.flyted.BatchWidget.prototype.clear = function() {
    var _context = "flyui.flyted.BatchWidget.prototype.clear";
    try {
        
        flyui.debug("clear", _context);
        this._controller.clear();
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
}









/*
 * ----------------------------------------------------------------
 *                             CONTROLLER
 * ----------------------------------------------------------------
 */






/**
 * @class
 */
flyui.flyted.BatchWidget.Controller = function( model, service, controllee ) {
    var _context = "flyui.flyted.BatchWidget.Controller";
    try {
        
        this._model = null;
        this._service = null;
        this._controllee = null;
        
        flyui.debug("call private constructor", _context);
        this.__init__(model, service, controllee);        
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};








/**
 * @private
 */
flyui.flyted.BatchWidget.Controller.prototype.__init__ = function( model, service, controllee ) {
    var _context = "flyui.flyted.BatchWidget.Controller.prototype.__init__";
    try {
        
        this._model = model;
        this._service = service;
        this._controllee = controllee;
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};








/**
 * @public
 */
flyui.flyted.BatchWidget.Controller.prototype.findImagesByGeneBatch = function( querynames, genes ) {
    var _context = "flyui.flyted.BatchWidget.Controller.prototype.findGenesByAnyNameBatch";
    try {
        
        flyui.info("findImagesByGeneBatch: "+querynames+" || "+genes, _context);
        flyui.debug("pass through to private implementation", _context);
        this._findImagesByGeneBatch(querynames, genes, this._findImagesByGeneBatchSuccess(), this._findImagesByGeneBatchFailure());
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};








/**
 * @private
 */
flyui.flyted.BatchWidget.Controller.prototype._findImagesByGeneBatch = function( querynames, genes, success, failure ) {
    var _context = "flyui.flyted.BatchWidget.Controller.prototype._findImagesByGeneBatch";
    try {
        
        flyui.debug("querynames: "+querynames, _context);
        flyui.debug("genes: "+genes, _context);
        
        flyui.debug("set state pending", _context);
        this._model.set("STATE", "PENDING");
        
        flyui.debug("set model property query", _context);
        this._model.set("QUERY", [querynames, genes]);

        flyui.debug("set result null", _context);
        this._model.set("RESULTS", null);
                
        flyui.debug("set message null", _context);
        this._model.set("MESSAGE", null);
                
        var flybaseids = [];
        for (var i=0;i<genes.length;i++) {
            flybaseids[i] = genes[i].flybaseID;
        }
        flyui.debug("kick off request: "+flybaseids, _context);
        this._service.findImagesByFlybaseGeneIDBatch(flybaseids, success, failure);        
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};









/**
 * @private
 */
flyui.flyted.BatchWidget.Controller.prototype._findImagesByGeneBatchSuccess = function() {
    var _context = "flyui.flyted.BatchWidget.Controller.prototype._findImagesByGeneBatchSuccess";
    var self = this;
    /**
     */
    return function( results ) {
        try {
            
            flyui.info("request success", _context);
            
            flyui.debug("set model results", _context);
            self._model.set("RESULTS", results);
            
            flyui.debug("set model state", _context);
            self._model.set("STATE", "READY");
            
            var explanation = "Images depict expression patterns of genes involved in spermatogenesis in the testes of Drosophila melanogaster. Empty table cells indicate that no images are available from FlyTED for that gene. See also Carine Barreau, Elizabeth Benson, Elin Gudmannsdottir and Helen White-Cooper, <a href='http://dev.biologists.org/cgi/content/full/135/11/1897'>Post-meiotic transcription in Drosophila testes</a>, Development. 2008 Jun;135(11):1897-902.";
            self._model.set("MESSAGE", explanation);
            
        } catch (unexpected) {
            flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
            throw unexpected;    
        }
    };
};







/**
 * @private
 */
flyui.flyted.BatchWidget.Controller.prototype._findImagesByGeneBatchFailure = function() {
    var _context = "flyui.flyted.BatchWidget.Controller.prototype._findImagesByGeneBatchFailure";
    var self = this;
    /**
     * @param {ResponseObject} response
     */
    return function( response ) {
        try {
            
            flyui.err("request failed: "+response.status+" "+response.statusText, _context);
            self._model.set("MESSAGE", "there was an error retrieving data from the server, see the logs for more info");
            self._model.set("STATE", "SERVERERROR");
            
        } catch (unexpected) {
            flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
            throw unexpected;    
        }
    };
};






flyui.flyted.BatchWidget.Controller.prototype.clear = function() {
    var _context = "flyui.flyted.BatchWidget.Controller.prototype.clear";
    try {
        
        flyui.debug("clear", _context);

        flyui.debug("set state ready", _context);
        this._model.set("STATE", "READY");
        
        flyui.debug("set model property query", _context);
        this._model.set("QUERY", null);

        flyui.debug("set result null", _context);
        this._model.set("RESULTS", null);
                
        flyui.debug("set message null", _context);
        this._model.set("MESSAGE", null);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
}








/*
 * ----------------------------------------------------------------
 *                             MODEL DEFINITION
 * ----------------------------------------------------------------
 */





/** 
 * @type Object
 */
flyui.flyted.BatchWidget.modelDefinition = {

    properties : [ "STATE", "RESULTS", "MESSAGE", "QUERY" ],
    
    values : {
        "STATE" : [ "READY", "PENDING", "SERVERERROR", "UNEXPECTEDERROR" ]
    },
    
    initialize : function( data ) {
        data["STATE"] = "READY";
        data["RESULTS"] = null;
        data["MESSAGE"] = null;
        data["QUERY"] = null;
    }

};







/*
 * ----------------------------------------------------------------
 *                             DEFAULT RENDERER
 * ----------------------------------------------------------------
 */







flyui.flyted.BatchWidget.DefaultRenderer = function() {};


/** 
 * @private 
 * @type Element
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._canvas = null;

/**
 * @private 
 * @type Element
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._pendingPane = null;

/**
 * @private 
 * @type Element
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._resultsSummaryPane = null;

/**
 * @private 
 * @type Element
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._resultsPane = null;

/**
 * @private 
 * @type Element
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._messagePane = null;





/**
 * Set the DOM element to which this renderer applies and initialise it.
 * @param {Element} canvas
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype.setCanvas = function( canvas ) {
    var _context = "flyui.flyted.BatchWidget.DefaultRenderer.prototype.setCanvas";
    try {
        
        flyui.debug("set canvas", _context);
        this._canvas = $(canvas);
        this._initCanvas();
        
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};






/**
 * @private
 * @param {Element} canvas
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._initCanvas = function() {
    var _context = "flyui.flyted.BatchWidget.DefaultRenderer.prototype._initCanvas";
    try {
        
        flyui.debug("begin init canvas", _context);
        
        var canvas = this._canvas;
        canvas.addClass("batchFlytedImageWidget");

        var pp = $("<p class='pendingPane'>pending (please wait, this can take up to 10 seconds) ...</p>").hide();
        canvas.append(pp);
        this._pendingPane = pp;

        var rsp = $("<p class='resultsSummaryPane'>this text should never be displayed</p>").hide();
        canvas.append(rsp);
        this._resultsSummaryPane = rsp;
        
        var rp = $("<div class='resultsPane'></div>").hide();
        canvas.append(rp);
        this._resultsPane = rp;
        
        var mp = $("<p class='messagePane'>this text should never be displayed</p>").hide();
        canvas.append(mp);
        this._messagePane = mp;            

        flyui.debug("init canvas done", _context);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};





/**
 * @public
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype.connect = function( model ) {
    var _context = "flyui.flyted.BatchWidget.DefaultRenderer.prototype.connect";
    try {
        
        flyui.debug("connect to model", _context);
        model.subscribeAll(this._onModelChanged, this);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};





/**
 * @private
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._onModelChanged = function( type, args, self ) {
    var _context = "flyui.flyted.BatchWidget.DefaultRenderer.prototype._onModelChanged";
    try {
        
        var handlers = {
            "STATE":"_onStateChanged",
            "QUERY":"_onQueryChanged",
            "RESULTS":"_onResultsChanged",
            "MESSAGE":"_onMessageChanged"
        };
        var handler = handlers[type];
        flyui.debug("call model changed handler: "+handler, _context);
        self[handler](args[0], args[1], args[2]);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};






/**
 * @private
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._onQueryChanged = function( from, to, get ) {
    var _context = "flyui.flyted.BatchWidget.DefaultRenderer.prototype._onQueryChanged";
    try {
        
        // do nothing, we will access the value later
        flyui.debug("query changed from "+from+" to "+to, _context);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};






/**
 * @private
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._onStateChanged = function( from, to, get ) {
    var _context = "flyui.flyted.BatchWidget.DefaultRenderer.prototype._onStateChanged";
    try {
        
        flyui.debug("state changed from "+from+" to "+to, _context);

        if ( to == "PENDING" ) {
            this._pendingPane.show();
            this._messagePane.hide();
            this._resultsSummaryPane.hide();
            this._resultsPane.hide();
        }
        else if ( to == "READY" ) {
            this._pendingPane.hide();
            this._messagePane.show();
            this._resultsSummaryPane.show();
            this._resultsPane.show();         
        } 
        else if ( to == "SERVERERROR" || to == "UNEXPECTEDERROR" ) {
            this._pendingPane.hide();
            this._messagePane.show();
            this._resultsSummaryPane.hide();
            this._resultsPane.hide();         
        } 
        else {
            // this should never happen
            throw {message:"invalid state: "+to};
        }
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};






/**
 * @private
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._onResultsChanged = function( from, to, get ) {
    var _context = "flyui.flyted.BatchWidget.DefaultRenderer.prototype._onResultsChanged";
    try {
        
        flyui.debug("results changed to: "+to, _context);
        
        if (to == null) {
            flyui.debug("empty results summary pane", _context);
            this._resultsSummaryPane.empty();
            flyui.debug("empty results pane", _context);
            this._resultsPane.empty();
        } 
        
        else {

            var query = get("QUERY");
            
            flyui.debug("render results summary", _context);
            this._renderResultsSummary(query, to);
    
            flyui.debug("render results", _context);
            this._renderResults(query, to);        
            
        }
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};







/**
 * @private
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._onMessageChanged = function( from, to, get ) {
    var _context = "flyui.flyted.BatchWidget.DefaultRenderer.prototype._onMessageChanged";
    try {
        
        flyui.debug("message changed to: "+to, _context);
        
        if (to == null) {
            flyui.debug("empty messsage pane", _context);
            this._messagePane.empty();
        } 
        
        else {

            this._messagePane.html(to);
            
        }
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};









/**
 * @private
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._renderResultsSummary = function( query, results ) {
    var _context = "flyui.flyted.BatchWidget.DefaultRenderer.prototype._renderResultsSummary";
    try {
        
        flyui.debug("render results summary", _context);

        var querynames = query[0];
        var genes = query[1];
        
        var count = 0;
        
        for (genename in results) {
            flyui.debug("counting images for "+genename, _context);
            count += results[genename].images.length;               
        }
        
        var content = "found "+count+" images from <a href='http://www.fly-ted.org'>www.fly-ted.org</a> ("+flyui.flyted.provenance+") ...";

        this._resultsSummaryPane.html(content);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};








/**
 * @private
 */
flyui.flyted.BatchWidget.DefaultRenderer.prototype._renderResults = function( query, results ) {
    var _context = "flyui.flyted.BatchWidget.DefaultRenderer.prototype._renderResults";
    try {
        flyui.debug("render results", _context);

        // query has both anyNames + geneObjects
        
        // querynames: anyNames
        var querynames = query[0];
        // genes; gene objects
        var genes = query[1];
        
        var content = "<table>";

        content += "<thead><tr><th>gene</th><th>images</th></tr></thead><tbody>";
        
        for (var i=0; i<querynames.length; i++) {
            var n = querynames[i];
            var c = genes[i].annotationSymbols[0];
            var id = genes[i].flybaseID;

            content += "<tr><td>" + n + "</td><td>"; // use query name because that's what the user asked for

            // TODO add links to flyted gene report pages? or not?
                        
            flyui.debug("looking for results for gene "+id, _context);
            
            var fbgn = "http://openflydata.org/id/flybase/feature/" + id ;
            
            if (typeof results[fbgn] != "undefined" || results[fbgn]) {
                var imgs = results[fbgn].images;
                
                flyui.debug("found images "+imgs.length+" in result for gene "+id, _context);
                
    //            content += imgs.length ;
                
                for (var image in imgs) {
            	    var alttext = "thumbnail image depicting expression of "+imgs[image].caption;
                    flyui.debug("found image "+image+" in result for gene "+id, _context);
                    flyui.debug("found image "+imgs[image].flytedURL+" in result for gene "+id, _context);
                    content +=   "<div class=\"result\">";
                    content +=          "<a href=\"" + imgs[image].flytedURL + "\">";
                    content +=              "<img src=\"" + imgs[image].thumbnailURL + "\" alt=\""+alttext+"\">";
                    content +=          "</img></a>"; 
                    content +=          "<p class=\"caption\">"+imgs[image].caption+"</p>"
                    content +=      "</div>";
                }
            }
            
            content += "</td></tr>";
        }

        content += "</tbody></table>";
        
        flyui.debug("results pane content: "+content, _context);
        this._resultsPane.html(content);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};




























